home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / kernel / util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-13  |  12.5 KB  |  612 lines  |  [TEXT/KAHL]

  1. /* Random utilities not classifiable elsewhere.
  2.    Copyright (C) 1987, 88, 89, 91, 92, 93, 1994 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. #include "config.h"
  10. #include "misc.h"
  11. #include "lisp.h"
  12. #include "dir.h"
  13. int multiply_dice PROTO ((int dice, int mult));
  14.  
  15. /* Accommodate certain obsolete (pre-ANSI) Unix systems. (?) */
  16.  
  17. #ifdef TIME_RETURNS_LONG
  18. #ifndef time_t
  19. #define time_t long
  20. #endif
  21. #endif
  22.  
  23. /* Direction-to-delta conversions. */
  24.  
  25. int dirx[] = DIRX;
  26. int diry[] = DIRY;
  27.  
  28. /* Random number handling is important to game but terrible/nonexistent
  29.    in some systems.  Do it ourselves and hope it's better.  Unfortunately,
  30.    it's hard to prevent clueless hackers from calling rand or random
  31.    and thereby confusing everything, so there (should be) is a check in
  32.    the test dir that searches for calls to these. */
  33.  
  34. /* The random state *must* be at least 32 bits. */
  35.  
  36. long initrandstate = -1;
  37.  
  38. long randstate = -1;
  39.  
  40. /* Seed can come from elsewhere, for repeatability.  Otherwise, it comes
  41.    from the current time, scaled down to where 32-bit arithmetic won't
  42.    overflow. */
  43.  
  44. void
  45. init_xrandom(seed)
  46. int seed;
  47. {
  48.     time_t tm;
  49.         
  50.     if (seed >= 0) {
  51.     /* If the random state is already set, changes are somewhat
  52.        suspicious. */
  53.     if (randstate >= 0) {
  54.         Dprintf("Randstate being changed from %d to %d\n",
  55.             randstate, seed);
  56.     }
  57.     randstate = seed;
  58.     } else {
  59.         time(&tm);
  60.         randstate = (long) tm;
  61.     }
  62.     /* Whatever its source, put the randstate into known range (0 - 99999). */
  63.     randstate = ABS(randstate);
  64.     randstate %= 100000L;
  65.     /* This is kept around for the sake of error reporting. */
  66.     initrandstate = randstate;
  67. }
  68.  
  69. /* Numbers lifted from Numerical Recipes, p. 198. */
  70. /* Arithmetic must be 32-bit. */
  71.  
  72. int
  73. xrandom(m)
  74. int m;
  75. {
  76.     randstate = (8121 * randstate + 28411) % 134456L;
  77.     return ((m * randstate) / 134456L);
  78. }
  79.  
  80. /* Percentage probability, with bounds checking. */
  81.  
  82. int
  83. probability(prob)
  84. int prob;
  85. {
  86.     if (prob <= 0) return FALSE;
  87.     if (prob >= 100) return TRUE;
  88.     return (xrandom(100) < prob);
  89. }
  90.  
  91. int
  92. roll_dice(n)
  93. int n;
  94. {
  95.     int numdice, dice, i, rslt;
  96.  
  97.     if (n >> 14 == 0 || n >> 14 == 3) return n;
  98.     numdice = (n >> 11) & 0x07;
  99.     dice = (n >> 7) & 0x0f;
  100.     rslt = n & 0x7f;
  101.     for (i = 0; i < numdice; ++i) {
  102.     rslt += xrandom(dice);
  103.     }
  104.     return rslt;
  105. }
  106.  
  107. int
  108. multiply_dice(n, mult)
  109. int n, mult;
  110. {
  111.     int numdice, dice, addend;
  112.  
  113.     if (n >> 14 == 0 || n >> 14 == 3)
  114.       return (n * mult) / 100;
  115.     numdice = (n >> 11) & 0x07;
  116.     dice = (n >> 7) & 0x0f;
  117.     dice = (dice * mult) / 100;
  118.     addend = ((n & 0x7f) * mult) / 100;
  119.     return (1 << 14) | (numdice << 11) | (dice << 7) | (addend & 0x7f);
  120. }
  121.  
  122. /* For a number in the range 0 - 10000, divide it by 100 and use the
  123.    remainder as the probability of adding 1. */
  124.  
  125. int
  126. prob_fraction(n)
  127. int n;
  128. {
  129.   return (n / 100 + (probability(n % 100) ? 1 : 0));
  130. }
  131.  
  132. #ifdef DEBUGGING
  133.  
  134. /* This tracks our total space allocation. */
  135.  
  136. #define NUMMALLOCRECS 100
  137.  
  138. int overflow = 0;
  139.  
  140. int totmalloc = 0;
  141.  
  142. int nextmalloc = 0;
  143.  
  144. int copymalloc = 0;
  145.  
  146. int grandtotmalloc = 0;
  147.  
  148. struct a_malloc {
  149.     int size;
  150.     int count;
  151. } *mallocs = NULL;
  152.  
  153. static void record_malloc PROTO ((int amt));
  154. static int malloc_record_compare PROTO ((const void *m1, const void *m2));
  155.  
  156. /* Given an amount of memory allocated, record it with the others. */
  157.  
  158. static void
  159. record_malloc(amt)
  160. int amt;
  161. {
  162.     int i;
  163.  
  164.     /* Might need to allocate the record of allocations. */
  165.     if (mallocs == NULL) {
  166.     /* Don't use xmalloc here!! */
  167.     mallocs = (struct a_malloc *)
  168.       malloc(NUMMALLOCRECS * sizeof(struct a_malloc));
  169.     overflow = 0;
  170.     }
  171.     /* Search for already-recorded allocations of same-size blocks. */
  172.     for (i = 0; i < nextmalloc; ++i) {
  173.     if (amt == mallocs[i].size) {
  174.         ++(mallocs[i].count);
  175.         return;
  176.     }
  177.     }
  178.     if (nextmalloc < NUMMALLOCRECS) {
  179.     /* Record this allocation as a new size of allocation. */
  180.     mallocs[nextmalloc].size = amt;
  181.     mallocs[nextmalloc].count = 1;
  182.     ++nextmalloc;
  183.     } else {
  184.         /* Add to the overflow bucket, which is used for allocations whose
  185.        sizes could not be recorded individually. */
  186.         overflow += amt;
  187.     }
  188. }
  189.  
  190. static int
  191. malloc_record_compare(m1, m2)
  192. CONST void *m1, *m2;
  193. {
  194.     return (((struct a_malloc *) m1)->size * ((struct a_malloc *) m1)->count
  195.             - ((struct a_malloc *) m2)->size * ((struct a_malloc *) m2)->count);
  196. }
  197.  
  198. /* Display memory consumption and reset records.  This does not account
  199.    for freeing, but Xconq usually tries to hang onto and reuse anything
  200.    it allocates, very rarely calls free(). */
  201.  
  202. void
  203. report_malloc()
  204. {
  205.     extern int lispmalloc, numsymbols, maxsymbols;
  206.     int i;
  207.  
  208.     if (nextmalloc == 0) {
  209.     Dprintf("No mallocs since last report.\n");
  210.     return;
  211.     }
  212.     Dprintf("Mallocs since last report:\n");
  213.     Dprintf("    Amount =  Bytes x  Times\n");
  214.     /* Sort the entries. */
  215.     qsort(mallocs, nextmalloc, sizeof(struct a_malloc), malloc_record_compare);
  216.     /* Write out all the records, formatting nicely. */
  217.     for (i = 0; i < nextmalloc; ++i) {
  218.     Dprintf("%10d = %6d x %6d\n",
  219.         mallocs[i].size * mallocs[i].count,
  220.         mallocs[i].size,  mallocs[i].count);
  221.     }
  222.     if (overflow > 0) Dprintf("%10d other\n", overflow);
  223.     Dprintf("Total malloced = %d bytes.\n", totmalloc);
  224.     Dprintf("String copies = %d bytes.\n", copymalloc);
  225.     Dprintf("Lisp malloced = %d bytes.\n", lispmalloc);
  226.     Dprintf("%d/%d symbols interned.\n", numsymbols, maxsymbols);
  227.     Dprintf("Grand total allocation = %d bytes.\n", grandtotmalloc);
  228.     /* Reset all the counters for next time. */
  229.     nextmalloc = overflow = 0;
  230.     totmalloc = copymalloc = lispmalloc = 0;
  231. }
  232.  
  233. #endif /* DEBUGGING */
  234.  
  235. /* This is our improved and adapted version of malloc, that guarantees
  236.    zeroing of the block, checks for memory exhaustion, and collects
  237.    usage statistics. */
  238.  
  239. char *
  240. xmalloc(amt)
  241. int amt;
  242. {
  243.     char *value = (char *) malloc(amt);
  244.  
  245.     if (value == NULL) {
  246.     /* This is pretty serious, have to get out quickly. */
  247.     run_error("Memory exhausted!!");
  248.     /* In case run_error doesn't exit. */
  249.       exit(1);
  250.     }
  251.     /* Save callers from having to clear things themselves. */
  252.     memset(value, 0, amt);
  253. #ifdef DEBUGGING
  254.     /* This can't be controlled by `Debug', because much allocation
  255.        happens before any command line or dialog options are interpreted. */
  256.     totmalloc += amt;
  257.     grandtotmalloc += amt;
  258.     record_malloc(amt);
  259. #endif
  260.     return value;
  261. }
  262.  
  263. /* Like sprintf, but appends. */
  264.  
  265. #ifdef __STDC__
  266. void
  267. tprintf(char *buf, char *str, ...)
  268. {
  269.     va_list ap;
  270.     char line[300];
  271.  
  272.     va_start(ap, str);
  273.     vsprintf(line, str, ap);
  274.     strcat(buf, line);
  275.     va_end(ap);
  276. }
  277.  
  278. void
  279. tnprintf(char *buf, int n, char *str, ...)
  280. {
  281.     va_list ap;
  282.     int n1 = n - strlen(buf);
  283.     char line[300];
  284.  
  285.     if (n1 > 0) {
  286.     va_start(ap, str);
  287.     vsprintf(line, str, ap);
  288.     strncat(buf, line, n1);
  289.     va_end(ap);
  290.     }
  291. }
  292.  
  293. void
  294. vtprintf(char *buf, char *str, va_list ap)
  295. {
  296.     char line[300];
  297.  
  298.     vsprintf(line, str, ap);
  299.     strcat(buf, line);
  300. }
  301. #else
  302. void
  303. tprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  304. char *buf, *str;
  305. long a1, a2, a3, a4, a5, a6, a7, a8, a9;
  306. {
  307.     char line[300];
  308.  
  309.     sprintf(line, str, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  310.     strcat(buf, line);
  311. }
  312.  
  313. void
  314. tnprintf(buf, n, str, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  315. char *buf, *str;
  316. int n;
  317. long a1, a2, a3, a4, a5, a6, a7, a8, a9;
  318. {
  319.     int n1 = n - strlen(buf);
  320.     char line[300];
  321.  
  322.     if (n1 > 0) {
  323.     sprintf(line, str, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  324.     strncat(buf, line, n1);
  325.     }
  326. }
  327. #endif
  328.  
  329. /* Copy a string to newly-allocated space.  The new space is never freed. */
  330.  
  331. char *
  332. copy_string(str)
  333. char *str;
  334. {
  335.     int len = strlen(str);
  336.     char *rslt;
  337.  
  338.     rslt = xmalloc(len + 1);
  339.     strcpy(rslt, str);
  340. #ifdef DEBUGGING
  341.     copymalloc += len + 1;
  342. #endif
  343.     return rslt;
  344. }
  345.  
  346. /* Get a *numeric* index into a string (more useful than ptr, in Xconq).
  347.    Return -1 on failed search. */
  348.  
  349. int
  350. iindex(ch, str)
  351. int ch;
  352. char *str;
  353. {
  354.     int i;
  355.  
  356.     if (str == NULL) return (-1);
  357.     for (i = 0; str[i] != '\0'; ++i) if (ch == str[i]) return i;
  358.     return (-1);
  359. }
  360.  
  361. /* Return a time difference as an long integer number of seconds. */
  362.  
  363. long
  364. idifftime(t1, t0)
  365. time_t t1, t0;
  366. {
  367. #ifdef MAC /* (should be anywhere that actually has a difftime function) */
  368.     return ((long) difftime(t1, t0));
  369. #else
  370.     return ((long) t1 - (long) t0);
  371. #endif
  372. }
  373.  
  374. /* This little routine goes at the end of all switch statements on internal
  375.    data values. */
  376.  
  377. void
  378. case_panic(str, var)
  379. char *str;
  380. int var;
  381. {
  382.     run_error("Panic! Unknown %s %d", str, var);
  383. }
  384.  
  385. /* Integer square root - good enough, no float trickery or libs needed. */
  386.  
  387. /* Improved version from Bruce Fast, via Scott Herod. */
  388.  
  389. int
  390. isqrt(i)
  391. int i;
  392. {
  393.     int j, k;
  394.  
  395.     if (i > 3) {
  396.         for (j = i, k = -1; j >>= 2; k <<= 1);
  397.         k = (~k + i / ~k) / 2;
  398.     k = (k + i / k) / 2;
  399.     k = (1 + k + i / k) / 2;
  400.     return (k + i / k) / 2;
  401.     } else if (i > 0) {
  402.     return 1;
  403.     } else {
  404.     return 0;
  405.     }
  406. }
  407.  
  408. #ifdef DEBUGGING
  409.  
  410. /* Debugging flags.
  411.    These are set up so that they can be macros or variables, as desired. */
  412.  
  413. #ifndef Debug
  414. int Debug = FALSE;
  415. #endif
  416. #ifndef DebugM
  417. int DebugM = FALSE;
  418. #endif
  419. #ifndef DebugG
  420. int DebugG = FALSE;
  421. #endif
  422.  
  423. /* These are where normal debugging output goes. */
  424.  
  425. FILE *pfp;
  426. FILE *dfp;
  427. FILE *dgfp;
  428. FILE *dmfp;
  429.  
  430. #ifdef __STDC__
  431. void
  432. profile_printf(char *str, ...)
  433. {
  434.     va_list ap;
  435.  
  436.     va_start(ap, str);
  437.     vfprintf(pfp, str, ap);
  438.     va_end(ap);
  439. }
  440.  
  441. void
  442. debug_printf(char *str, ...)
  443. {
  444.     va_list ap;
  445.  
  446.     va_start(ap, str);
  447.     vfprintf(dfp, str, ap);
  448.     va_end(ap);
  449. }
  450.  
  451. void
  452. debugm_printf(char *str, ...)
  453. {
  454.     va_list ap;
  455.  
  456.     va_start(ap, str);
  457.     vfprintf(dmfp, str, ap);
  458.     va_end(ap);
  459. }
  460.  
  461. void
  462. debugg_printf(char *str, ...)
  463. {
  464.     va_list ap;
  465.  
  466.     va_start(ap, str);
  467.     vfprintf(dgfp, str, ap);
  468.     va_end(ap);
  469. }
  470. #else
  471. /* Kind of cheesy, should only use if real ANSI not available. */
  472.  
  473. void
  474. profile_printf(str, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12)
  475. char *str;
  476. long a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12;
  477. {
  478.     fprintf(pfp, str, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
  479. }
  480.  
  481. void
  482. debug_printf(str, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12)
  483. char *str;
  484. long a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12;
  485. {
  486.     fprintf(dfp, str, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
  487. }
  488.  
  489. void
  490. debugm_printf(str, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12)
  491. char *str;
  492. long a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12;
  493. {
  494.     fprintf(dmfp, str, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
  495. }
  496.  
  497. void
  498. debugg_printf(str, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12)
  499. char *str;
  500. long a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12;
  501. {
  502.     fprintf(dgfp, str, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
  503. }
  504. #endif /* __STDC__ */
  505.  
  506. #endif /* DEBUGGING */
  507.  
  508. void
  509. #ifdef __STDC__
  510. init_error(char *str, ...)
  511. #else
  512. init_error(str, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  513. char *str;
  514. long a1, a2, a3, a4, a5, a6, a7, a8, a9;
  515. #endif
  516. {
  517.     char buf[BUFSIZE];
  518.  
  519. #ifdef __STDC__
  520.     {
  521.     va_list ap;
  522.  
  523.     va_start(ap, str);
  524.     vsprintf(buf, str, ap);
  525.     va_end(ap);
  526.     }
  527. #else
  528.     sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  529. #endif
  530.     low_init_error(buf);
  531. }
  532.  
  533. void
  534. #ifdef __STDC__
  535. init_warning(char *str, ...)
  536. #else
  537. init_warning(str, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  538. char *str;
  539. long a1, a2, a3, a4, a5, a6, a7, a8, a9;
  540. #endif
  541. {
  542.     char buf[BUFSIZE];
  543.  
  544. #ifdef __STDC__
  545.     {
  546.     va_list ap;
  547.  
  548.     va_start(ap, str);
  549.     vsprintf(buf, str, ap);
  550.     va_end(ap);
  551.     }
  552. #else
  553.     sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  554. #endif
  555.     low_init_warning(buf);
  556. }
  557.  
  558. /* A run error is fatal. */
  559.  
  560. void
  561. #ifdef __STDC__
  562. run_error(char *str, ...)
  563. #else
  564. run_error(str, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  565. char *str;
  566. long a1, a2, a3, a4, a5, a6, a7, a8, a9;
  567. #endif
  568. {
  569.     char buf[BUFSIZE];
  570.  
  571. #ifdef __STDC__
  572.     {
  573.     va_list ap;
  574.  
  575.     va_start(ap, str);
  576.     vsprintf(buf, str, ap);
  577.     va_end(ap);
  578.     }
  579. #else
  580.     sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  581. #endif
  582.     low_run_error(buf);
  583. }
  584.  
  585. /* Runtime warnings are for when it's important to bug the players,
  586.    usually a problem with Xconq or a game design. */
  587.  
  588. void
  589. #ifdef __STDC__
  590. run_warning(char *str, ...)
  591. #else
  592. run_warning(str, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  593. char *str;
  594. long a1, a2, a3, a4, a5, a6, a7, a8, a9;
  595. #endif
  596. {
  597.     char buf[BUFSIZE];
  598.  
  599. #ifdef __STDC__
  600.     {
  601.     va_list ap;
  602.  
  603.     va_start(ap, str);
  604.     vsprintf(buf, str, ap);
  605.     va_end(ap);
  606.     }
  607. #else
  608.     sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  609. #endif
  610.     low_run_warning(buf);
  611. }
  612.